package cn.baiweigang.uu.strategy.linearswap;

import cn.baiweigang.uu.enums.PeriodEnum;
import cn.baiweigang.uu.model.KLineInfo;
import cn.baiweigang.uu.utils.DateUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

public class KLineList<E> extends LinkedList {
    private PeriodEnum periodEnum;
    private KLineInfo openMax;//开盘价最大
    private KLineInfo openMin;//开盘价最小
    private KLineInfo closeMax;//收盘价最大
    private KLineInfo closeMin;//收盘价最小
    private KLineInfo highMax;//最高价最大
    private KLineInfo hignMin;//最高价最小
    private KLineInfo lowMax;//最低价最大
    private KLineInfo lowMin;//最低价最小

    private BigDecimal changeVol;//周期内 涨跌量
    private BigDecimal changeRate;//周期内 涨跌率 百分比
    private BigDecimal swingVol;//周期内  波动量
    private BigDecimal swingRate;//周期内 波动率 百分比

    /**
     * 只能用此方法添加
     *
     * @param e
     * @return
     */
    @Override
    public boolean add(Object e) {
        boolean result = super.add(e);
//        //更新下最新加入的
        calculate(getLast());
        return result;
    }

    public void refreshAll() {
        for (int i = 0; i < size(); i++) {
            KLineInfo kLineInfo = get(i);
            //更新最大最小
            if (openMax == null) openMax = kLineInfo;
            if (openMin == null) openMin = kLineInfo;
            if (kLineInfo.getOpen().subtract(openMax.getOpen()).intValue() > 0) openMax = kLineInfo;
            if (openMin.getOpen().subtract(kLineInfo.getOpen()).intValue() > 0) openMin = kLineInfo;

            if (closeMax == null) closeMax = kLineInfo;
            if (closeMin == null) closeMin = kLineInfo;
            if (kLineInfo.getClose().subtract(closeMax.getClose()).intValue() > 0) closeMax = kLineInfo;
            if (closeMin.getClose().subtract(kLineInfo.getClose()).intValue() > 0) closeMin = kLineInfo;

            if (highMax == null) highMax = kLineInfo;
            if (hignMin == null) hignMin = kLineInfo;
            if (kLineInfo.getHigh().subtract(highMax.getHigh()).intValue() > 0) highMax = kLineInfo;
            if (hignMin.getHigh().subtract(kLineInfo.getHigh()).intValue() > 0) hignMin = kLineInfo;

            if (lowMax == null) lowMax = kLineInfo;
            if (lowMin == null) lowMin = kLineInfo;
            if (kLineInfo.getLow().subtract(lowMax.getLow()).intValue() > 0) lowMax = kLineInfo;
            if (lowMin.getLow().subtract(kLineInfo.getLow()).intValue() > 0) lowMin = kLineInfo;
        }

        //技术周期内波动和涨跌幅
        if (size() > 0) {
            changeVol = getLast().getOpen().subtract(getFirst().getOpen());
            changeRate = changeVol.multiply(BigDecimal.valueOf(100)).
                    divide(getFirst().getOpen(), 3, RoundingMode.CEILING);
            swingVol = highMax.getHigh().subtract(lowMin.getLow());
            swingRate = swingVol.multiply(BigDecimal.valueOf(100)).
                    divide(getFirst().getOpen(), 3, RoundingMode.CEILING);

            //最后1个元素 判断比前几个连续大或连续小 的个数
            getLast().setGreaterPreCount(comparePreGreater(getLast(), true));
            getLast().setLessPreCount(comparePreGreater(getLast(), false));
        }
    }

    private void calculate(KLineInfo kLineInfo) {
        //计算指标
        kLineInfo.setDateTime(DateUtil.formatDateYMDHMS(new Date(kLineInfo.getId() * 1000)));
        kLineInfo.setChangeVol(kLineInfo.getClose().subtract(kLineInfo.getOpen()));
        kLineInfo.setChangeRate(kLineInfo.getChangeVol().multiply(BigDecimal.valueOf(100)).
                divide(kLineInfo.getOpen(), 3, RoundingMode.CEILING));
        kLineInfo.setSwingVol(kLineInfo.getHigh().subtract(kLineInfo.getLow()));
        kLineInfo.setSwingRate(kLineInfo.getSwingVol().multiply(BigDecimal.valueOf(100)).
                divide(kLineInfo.getOpen(), 3, RoundingMode.CEILING));
    }

    private int comparePreGreater(KLineInfo kLineInfo, boolean greater) {
        int lastIndex = this.size() - 2;
        int num = 0;
        for (int i = lastIndex; i >= 0; i--) {
            if ((kLineInfo.getClose().subtract(get(i).getClose()).intValue() >= 0) == greater) {
                num++;
            } else {
                break;
            }
        }
        return num;
    }

    @Override
    public KLineInfo getFirst() {
        return (KLineInfo) super.getFirst();
    }

    @Override
    public KLineInfo getLast() {
        return (KLineInfo) super.getLast();
    }

    @Override
    public KLineInfo get(int index) {
        return (KLineInfo) super.get(index);
    }

    @Override
    public KLineInfo[] toArray() {
        return (KLineInfo[]) super.toArray();
    }

    /**
     * 获取后面几个
     *
     * @param num
     * @return
     */
    public KLineList<KLineInfo> getTail(int num) {
        return this.subList(size() - num, size());
    }

    public KLineList<KLineInfo> subList(int fromIndex, int toIndex) {
        List<KLineInfo> tempList = super.subList(fromIndex, toIndex);
        KLineList<KLineInfo> kLineList = new KLineList<>();
        kLineList.setPeriodEnum(this.periodEnum);
        for (KLineInfo kLineInfo : tempList) {
            kLineList.add(kLineInfo);
        }
        return kLineList;
    }

    public PeriodEnum getPeriodEnum() {
        return periodEnum;
    }

    public void setPeriodEnum(PeriodEnum periodEnum) {
        this.periodEnum = periodEnum;
    }

    public KLineInfo getOpenMax() {
        return openMax;
    }

    public KLineInfo getOpenMin() {
        return openMin;
    }

    public KLineInfo getCloseMax() {
        return closeMax;
    }

    public KLineInfo getCloseMin() {
        return closeMin;
    }

    public KLineInfo getHighMax() {
        return highMax;
    }

    public KLineInfo getHignMin() {
        return hignMin;
    }

    public KLineInfo getLowMax() {
        return lowMax;
    }

    public KLineInfo getLowMin() {
        return lowMin;
    }

    public BigDecimal getChangeVol() {
        return changeVol;
    }

    public BigDecimal getChangeRate() {
        return changeRate;
    }

    public BigDecimal getSwingVol() {
        return swingVol;
    }

    public BigDecimal getSwingRate() {
        return swingRate;
    }
}
